package ms.unicorn.reasoning.optimize;

import java.util.BitSet;

public class AnnotatedAlternative implements Comparable<AnnotatedAlternative>  {

	BitSet nodes;
	float mb = 0;
	float rr = 0;
	private String evolutionPath = "";
	
	public AnnotatedAlternative(int leafCount) {
		nodes = new BitSet(leafCount);
	}
	
	public AnnotatedAlternative(BitSet nodes, float mb, float rr, String possibility) {
		this.nodes = (BitSet) nodes.clone();
		this.mb = mb;
		this.rr = rr;
		this.evolutionPath = possibility;
	}
	
	public AnnotatedAlternative(FDNode node, float mb, float rr) {
		this(node.getFDGraph().getLeafCount());
		assert node.getLeafID() >= 0;
		nodes.set(node.getLeafID());
		this.mb = mb;
		this.rr = rr;
	}

	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append('{');
		builder.append('}');
		return builder.toString();
	}
	
	public float getMaxBelief() {
		return mb;
	}

	public void setMaxBelief(float mb) {
		this.mb = mb;
	}

	public float getDeferalBelief() {
		return rr;
	}

	public void setRR(float rr) {
		this.rr = rr;
	}

	
	public String getEvolutionPath() {
		return this.evolutionPath;
	}
	
	public void setEvolutionPath(String possibility) {
		this.evolutionPath = possibility;
	}
	
	@Override
	public boolean equals(Object obj) {
		if (obj instanceof AnnotatedAlternative) {
			AnnotatedAlternative o = (AnnotatedAlternative) obj;
			return o.evolutionPath.equals(this.evolutionPath) && o.nodes.equals(nodes);
		}
		return super.equals(obj);
	}
	
	public boolean equals(AnnotatedAlternative o, boolean checkEvolutionPath) {
		return (checkEvolutionPath ? o.evolutionPath.equals(this.evolutionPath) : true) && o.nodes.equals(nodes);
	}
	
	public boolean subsumes(AnnotatedAlternative o, boolean checkEvolutionPath) {
		boolean result = checkEvolutionPath ? evolutionPath.equals(o.evolutionPath) : true;
		if (result) {
			BitSet temps = (BitSet) o.nodes.clone();
			temps.and(nodes);
			result = temps.equals(o.nodes);
		}
		return result;
	}

	public static AnnotatedAlternative join(AnnotatedAlternative a, AnnotatedAlternative b) {
		BitSet c = (BitSet) a.nodes.clone();
		c.or(b.nodes);
		
		return new AnnotatedAlternative(c, a.mb * b.mb, 1 - (1 - a.rr) * (1 - b.rr), a.evolutionPath + b.evolutionPath);
	}

	@Override
	public int compareTo(AnnotatedAlternative o) {
		int result = evolutionPath.compareTo(o.evolutionPath);
		if (result == 0) {
			long[] thisLong = nodes.toLongArray();
			long[] oLong = o.nodes.toLongArray();
			if (thisLong.length > oLong.length) {
				for (int i = oLong.length; i < thisLong.length; i++)
					if (thisLong[i] > 0) return 1;
			}
			else if (oLong.length > thisLong.length) {
				for (int i = thisLong.length; i < oLong.length; i++) 
					if (oLong[i] > 0) return -1;
			}
			int n = Math.min(thisLong.length, oLong.length);
			long lRes = 0;
			for (int i = n - 1; i>=0 && lRes == 0; i--)
				lRes = thisLong[i] - oLong[i];
			if (lRes > 0) return 1;
			if (lRes < 0) return -1;
		}
		return 0;
	}
}